package org.ns.framework.webmvc;

import org.ns.basics.commons.lang.StringUtils;
import org.ns.basics.commons.localex.LocaleService;
import org.ns.framework.webmvc.ResponseEntityKey.DefaultResponseEntityKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;

import javax.servlet.http.HttpServletRequest;
import java.util.Locale;

/**
 * 应答实体构造
 */
public class ResponseEntityBuild {

	private static final Logger log = LoggerFactory.getLogger(ResponseEntityBuild.class);

	private Integer httpStatus;

	private String requestId; // 请求ID(请求携带才会有)

	private Integer status; // 应答的数字展示状态

	private String state; // 应答状态--文字展示的状态

	private Object content; // 应答内容

	private String message; // 应答消息

	private String errplace; // 错误位置

	private String callback; // 函数回调

	private String localeMessage; // 国际化的 messageKey

	private Object[] messageArgs;

	private ResponseEntityKey entityKey;

	private ApplicationContext applicationContext;
	
	private Locale locale = Locale.ENGLISH;

	private ResponseEntityBuild() {
	}

	public static final ResponseEntityBuild create() {
		return new ResponseEntityBuild();
	}

	public ResponseEntityBuild setRequestId(String requestId) {
		this.requestId = requestId;
		return this;
	}

	public ResponseEntityBuild setHttpStatus(int httpStatus) {
		this.httpStatus = httpStatus;
		return this;
	}

	public ResponseEntityBuild setStatus(Integer status) {
		this.status = status;
		return this;
	}

	public ResponseEntityBuild setState(String state) {
		this.state = state;
		return this;
	}

	public ResponseEntityBuild setContent(Object content) {
		this.content = content;
		return this;
	}

	public ResponseEntityBuild setMessage(String message) {
		this.message = message;
		return this;
	}

	public ResponseEntityBuild setErrplace(String errplace) {
		this.errplace = errplace;
		return this;
	}

	public ResponseEntityBuild setCallback(String callback) {
		this.callback = callback;
		return this;
	}

	public ResponseEntityBuild setEntityKey(ResponseEntityKey entityKey) {
		this.entityKey = entityKey;
		return this;
	}

	public ResponseEntityBuild setResponseEntity(ResponseEntityBuild entityBuild) {
		if (entityBuild.httpStatus != null) {
			setHttpStatus(entityBuild.httpStatus);
		}
		if (StringUtils.isNotBlank(entityBuild.state)) {
			setState(entityBuild.state);
		}
		if (StringUtils.isNotBlank(entityBuild.requestId)) {
			setRequestId(entityBuild.requestId);
		}
		if (entityBuild.content != null) {
			setContent(entityBuild.content);
		}
		if (StringUtils.isNotBlank(entityBuild.message)) {
			setMessage(entityBuild.message);
		}
		if (StringUtils.isNotBlank(entityBuild.errplace)) {
			setErrplace(entityBuild.errplace);
		}
		if (StringUtils.isNotBlank(entityBuild.callback)) {
			setCallback(entityBuild.callback);
		}
		return this;
	}

	public ResponseEntityBuild setResponseEntity(ResponseEntity entity) {
		if (entity.getHttpStatus() != null) {
			setHttpStatus(entity.getHttpStatus());
		}
		if (StringUtils.isNotBlank(entity.getState())) {
			setState(entity.getState());
		}
		if (StringUtils.isNotBlank(entity.getRequestId())) {
			setRequestId(entity.getRequestId());
		}
		if (entity.getContent() != null) {
			setContent(entity.getContent());
		}
		if (StringUtils.isNotBlank(entity.getMessage())) {
			setMessage(entity.getMessage());
		}
		if (StringUtils.isNotBlank(entity.getErrplace())) {
			setErrplace(entity.getMessage());
		}
		if (StringUtils.isNotBlank(entity.getCallback())) {
			setCallback(entity.getCallback());
		}
		return this;
	}

	public ResponseEntityBuild setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
		return this;
	}

	public ResponseEntityBuild setLocaleMessage(String localeMessage) {
		this.localeMessage = localeMessage;
		return this;
	}

	public ResponseEntityBuild setMessageArgs(Object[] messageArgs) {
		this.messageArgs = messageArgs;
		return this;
	}
	
	public ResponseEntityBuild setLocale(Locale locale) {
		if (locale != null) {
			this.locale = locale;
		}
		return this;
	}
	public ResponseEntityBuild setLocale(String locale) {
		if (locale != null && locale.length() > 1) {
			this.locale = Locale.forLanguageTag(locale);
		}
		return this;
	}

    public ResponseEntity build() {
		ResponseEntityKey entityKey;
		if (this.entityKey != null) {
			entityKey = this.entityKey;
		} else {
			entityKey = DefaultResponseEntityKey.defaultInstance; 
		}
		String message = getMessage(null);
		return new ResponseEntity(httpStatus, requestId, status, state, content, message, errplace, callback,
				localeMessage, entityKey);
    }

	public ResponseEntity build(HttpServletRequest request) {
		if (request == null) {
			return build();
		}

		String callback = request.getParameter("callback");
		String requestId = request.getParameter("requestId");
		ResponseEntityKey entityKey;
		if (this.entityKey != null) {
			entityKey = this.entityKey;
		} else {
			entityKey = (ResponseEntityKey) request.getAttribute(ResponseEntityKey.KEY);
		}

		if (StringUtils.isBlank(requestId)) {
			requestId = request.getHeader("requestId");
		}
		if (StringUtils.isBlank(requestId)) {
			requestId = this.requestId;
		}
		if (StringUtils.isBlank(callback)) {
			callback = this.callback;
		}
		String message = getMessage(request);

		return new ResponseEntity(httpStatus, requestId, status, state, content, message, errplace, callback,
				localeMessage, entityKey);
	}

	/**
	 * 国际化操作
	 * 
	 * @param request
	 * @return
	 */
	private Locale getLocale(HttpServletRequest request) {
		if (request == null) {
			return this.locale;
		}
		Locale locale = (Locale) request.getAttribute("userLocale");
		if (locale == null) {
			String localeLanguage = request.getHeader("userLocale");
			if (localeLanguage == null || localeLanguage.length() < 2) {
				localeLanguage = request.getHeader("locale");
			}
			if (localeLanguage == null || localeLanguage.length() < 2) {
				localeLanguage = request.getHeader("Accept-Language");
			}
			if (localeLanguage != null && localeLanguage.length() > 1) {
				locale = Locale.forLanguageTag(localeLanguage);
				request.setAttribute("userLocale", locale);
			}
			if (locale == null) {
				locale = this.locale;
			}
		}
		return locale;
	}

	/**
	 * 获得国际化的 message
	 * 
	 * @return
	 */
	private String getMessage(HttpServletRequest request) {
		
		if (applicationContext == null) {
			return formatMessage();
		}
		if (localeMessage == null || localeMessage.isEmpty()) {
			return formatMessage();
		}
		Locale locale = getLocale(request);
		if (locale == null) {
			return formatMessage();
		}
		String message = getLocaleMessageByLocaleService(locale, localeMessage, messageArgs);
		if (message == null) {
			message = applicationContext.getMessage(localeMessage, messageArgs, formatMessage(), locale);
		}
		return message;
	}

	private String formatMessage() {
		if (message == null || message.isEmpty()) {
			return message;
		}
		try {
			if (messageArgs != null && messageArgs.length > 0) {
				return String.format(message, messageArgs);
			}
		} catch (Exception e) {
			log.error("responseBuildFormatMessage-ERROR", e);
		}
		return message;
	}

	private static LocaleService LOCALE_SERVICE;

	private LocaleService getLocaleService(ApplicationContext applicationContext) {
		if (LOCALE_SERVICE == null) {
			if (applicationContext != null && applicationContext.containsBean("localeService")) {
				try {
					LOCALE_SERVICE = applicationContext.getBean(LocaleService.class);
				} catch (Exception e) {
					log.error("", e);
				}
			}
			if (LOCALE_SERVICE == null) {
				LOCALE_SERVICE = LocaleService.EMPTY;
			}
		}
		return LOCALE_SERVICE;
	}

	private String getLocaleMessageByLocaleService(Locale locale, String key, Object ...args) {
		LocaleService localeService = getLocaleService(applicationContext);
		if (localeService == LocaleService.EMPTY) {
			return null;
		}
		return localeService.get(locale, key, args);
	}
}
